import { MongoMemoryServer } from 'mongodb-memory-server';
import mongoose, { Connection, ConnectOptions } from 'mongoose';
import { Db } from 'mongodb';
import { testHelpers } from '../utils/testHelpers';
import { logger } from '../utils/logger';

let mongod: MongoMemoryServer;

// 测试环境配置
export const setupTestEnvironment = async (): Promise<void> => {
  try {
    // 创建MongoDB内存服务器实例
    mongod = await MongoMemoryServer.create();
    const uri = mongod.getUri();

    // 设置环境变量
    process.env.NODE_ENV = 'test';
    process.env.MONGODB_URI = uri;
    process.env.JWT_SECRET = 'test-secret-key';
    process.env.LOG_LEVEL = 'error';

    // 连接到内存数据库
    await mongoose.connect(uri, {
      useNewUrlParser: true,
      useUnifiedTopology: true
    } as ConnectOptions);
    
    logger.info('Test environment setup completed', {
      mongoUri: uri,
      nodeEnv: process.env.NODE_ENV
    });
  } catch (error) {
    logger.error('Test environment setup failed:', error);
    throw error;
  }
};

// 清理测试环境
export const teardownTestEnvironment = async (): Promise<void> => {
  try {
    // 断开数据库连接
    await mongoose.disconnect();
    
    // 停止MongoDB内存服务器
    if (mongod) {
      await mongod.stop();
    }

    logger.info('Test environment teardown completed');
  } catch (error) {
    logger.error('Test environment teardown failed:', error);
    throw error;
  }
};

// 每个测试之间清理数据
export const clearTestData = async (): Promise<void> => {
  if (process.env.NODE_ENV !== 'test') {
    throw new Error('clearTestData can only be run in test environment');
  }

  try {
    const db = mongoose.connection.db;
    if (!db) {
      throw new Error('Database connection not established');
    }
    const collections = await db.collections();
    await Promise.all(collections.map(collection => collection.deleteMany({})));
    logger.info('Test data cleared');
  } catch (error) {
    logger.error('Failed to clear test data:', error);
    throw error;
  }
};

// 全局测试设置
beforeAll(async () => {
  await setupTestEnvironment();
});

// 每个测试之后清理数据
afterEach(async () => {
  await clearTestData();
});

// 全局测试清理
afterAll(async () => {
  await teardownTestEnvironment();
});
